package com.ye.personnel.common.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ye.personnel.api.constant.Constant;
import com.ye.personnel.common.exception.CustomerException;
import com.ye.personnel.common.response.ErrorCode;
import com.ye.personnel.mapper.entity.GwyAdminUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Date;

/**
 * @author ye
 * @Description
 * @create 2021-09-01 16:19
 */
@Slf4j
public class JwtUtil {

  public static final int EXPIRE_TIME = 7200;

  /**
   * 生成token
   * @param adminUser
   * @return
   */
  public static String createToken(GwyAdminUser adminUser) {

    Calendar nowTime = Calendar.getInstance();
    nowTime.add(Calendar.MINUTE,EXPIRE_TIME);
    Date expiresDate = nowTime.getTime();

    return JWT.create().withAudience(adminUser.getAdminUserId())   //签发对象
            .withIssuedAt(new Date())    //发行时间
            .withExpiresAt(expiresDate)  //有效时间
            .withClaim("departmentId", adminUser.getDepartmentId())    //载荷，随便写几个都可以
            .withClaim("userName", adminUser.getUserName())    //载荷，随便写几个都可以
            .withClaim("nickName", adminUser.getNickName())    //载荷，随便写几个都可以
            .sign(Algorithm.HMAC256(adminUser.getAdminUserId()+"pinnoocle"));   //加密
  }

  /**
   * 检验合法性，其中secret参数就应该传入的是用户的id
   * @param token
   * @param secret
   */
  public static void verifyToken(String token, String secret) {
    DecodedJWT jwt = null;
    try {
      JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret+"pinnoocle")).build();
      jwt = verifier.verify(token);
    } catch (Exception e) {
      //效验失败
      throw new CustomerException(ErrorCode.TOKEN_INVALID,"登录失效，请重新登录");
    }
  }

  /**
   * 获取签发对象
   * @param token
   * @return
   */
  public static String getAudience(String token){
    String audience = null;
    if(token == null){
      //这里是token解析失败
      throw new CustomerException(ErrorCode.TOKEN_INVALID,"登录失效，请重新登录");
    }
    try {
      audience = JWT.decode(token).getAudience().get(0);
    } catch (JWTDecodeException | IndexOutOfBoundsException j) {
      //这里是token解析失败
      throw new CustomerException(ErrorCode.TOKEN_INVALID,"登录失效，请重新登录");
    }
    return audience;
  }

  /**
   * 获取用户id
   * @return
   */
  public static String getLoginId(){
    HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
    if (request == null) {
      throw new CustomerException(ErrorCode.TOKEN_INVALID,"登录失效，请重新登录");
    }
    String token = request.getHeader(Constant.AUTHORIZATION);
    if(StringUtils.isEmpty(token)){
      throw new CustomerException(ErrorCode.TOKEN_INVALID,"登录失效，请重新登录");
    }
    String userId = getAudience(token);
    if(StringUtils.isEmpty(userId)){
      throw new CustomerException(ErrorCode.TOKEN_INVALID,"登录失效，请重新登录");
    }
    return userId;
  }


  /**
   * 获取指定载荷值
   * @return
   */
  public static String getDepartmentId(){
    HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
    if (request == null) {
      return null;
    }
    String token = request.getHeader(Constant.AUTHORIZATION);
    if(StringUtils.isEmpty(token)){
      return null;
    }
    Claim claimByName = getClaimByName(token, "departmentId");
    return claimByName.asString();
  }

  /**
   * 获取指定载荷值
   * @param keyName
   * @return
   */
  public static String getName(String keyName){
    HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
    if (request == null) {
      return null;
    }
    String token = request.getHeader(Constant.AUTHORIZATION);
    if(StringUtils.isEmpty(token)){
      return null;
    }
    Claim claimByName = getClaimByName(token, keyName);
    return claimByName.asString();
  }


  /**
   * 通过载荷名字获取载荷的值
   * @return
   */
  public static Claim getClaimByName(String token, String name){
    return JWT.decode(token).getClaim(name);
  }
}
